package com.example.martian.config.util;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Configuration
public class RedisUtils extends CachingConfigurerSupport {

    private RedisTemplate redisTemplate;

    public RedisUtils(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }



    @Autowired(required = true)
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * 修改Redis序列化方式，解决Redis可视化工具乱码问题
     *
     * @return
     */
    @Bean
    public RedisTemplate<String, List<Map<String, Object>>> redisTemplateInit() {
        RedisTemplate<String, List<Map<String, Object>>> template = new RedisTemplate<String, List<Map<String, Object>>>();
        template.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        template.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;
    }

    @Bean
    public RedisTemplate<String,String> redisTemplate() {

        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new RedisObjectSerializer());
        return redisTemplate;
    }


    /**
     * 从redis中取出一个键值
     *
     * @param key
     */
    public Object getDataFromCache(String key) {
        BoundValueOperations<String, Object> bound = redisTemplate.boundValueOps(key);
        return bound.get();
    }

    /**
     * 向redis添加一个键值
     *
     * @param key
     * @param data
     * @return
     */
    public void setDataToCache(String key, Object data) {
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(key);
        ops.set(data);
    }

    /**
     * 加入缓存，指定过期时间
     *
     * @param key
     * @return
     */
    public void setDataToCache(String key, Object data, long express) {
        BoundValueOperations<String, Object> ops = redisTemplate.boundValueOps(key);
        ops.set(data);
        ops.expire(express, TimeUnit.SECONDS);
    }

    /**
     * 清除缓存
     *
     * @param cacheKey
     */
    public void clearCache(String cacheKey) {
        redisTemplate.delete(cacheKey);
    }

    /**
     * 清除缓存
     * + *  可以清除多个
     * @param prex
     */
    public void clearPrexCache(String prex) {
        Set<String> keys = redisTemplate.keys(prex);
        redisTemplate.delete(keys);
    }

    /**
     * 查询key
     * @param prex   key
     */
    public Set<String> selectPrexCacheAll(String prex) {
        Set<String> keys = redisTemplate.keys(prex);
        return keys;
    }

    /**
     * 查询key
     * @param prex   key
     * @return
     */
    public Set<String> selectPrexCache(String prex) {
        Set<String> keys = redisTemplate.keys(prex + "*");
        return keys;
    }

    /**
     * 从缓存中获取一个list
     *
     * @param cacheKey
     * @return
     */
    public List<Object> getCacheList(String cacheKey) {
        BoundListOperations<String, Object> bound = redisTemplate.boundListOps(cacheKey);
        long size = bound.size();
        return bound.range(0, size);
    }

    /**
     * 在缓存中放入一个list<Map<String,Object></>></>
     *
     * @param cacheKey
     * @return
     */
    public void setCacheListInMap(String cacheKey,List<Map<String,Object>> maps){
        redisTemplateInit().opsForValue().set(cacheKey,maps);
    }

    /**
     * 在缓存中获取一个list<Map<String,Object></>></>
     *
     * @param cacheKey
     * @return
     */
    public List<Map<String,Object>> getCacheListInMap(String cacheKey){
        List<Map<String, Object>> maps = redisTemplateInit().opsForValue().get(cacheKey);
        return maps;
    }

    /**
     * 覆盖一个list
     *
     * @param cacheKey
     * @param dataList
     */
    public void updatCacheList(String cacheKey, List<Object> dataList) {
        redisTemplate.delete(cacheKey);
        BoundListOperations<String, Object> bound = redisTemplate.boundListOps(cacheKey);
        bound.rightPushAll(dataList.toArray());
    }

    /**
     * 获取一个hash
     * @param cacheKey
     * @return
     */
    public Map<String, Object> getCacheMap(String cacheKey) {
        BoundHashOperations<String, String, Object> bound = redisTemplate.boundHashOps(cacheKey);
        return bound.entries();
    }

    /**
     * 从hash里获取一个值
     *
     * @param cacheKey
     * @param key
     * @return
     */
    public Object getDataFromCacheMap(String cacheKey, Object key) {
        BoundHashOperations<String, Object, Object> bound = redisTemplate.boundHashOps(cacheKey);
        return bound.get(key);
    }

    /**
     * 向hash放进一个键值
     *
     * @param cacheKey
     * @param key
     * @param value
     */
    public void setDataFromCacheMap(String cacheKey, Object key, Object value) {
        BoundHashOperations<String, Object, Object> bound = redisTemplate.boundHashOps(cacheKey);
        bound.put(key, value);
    }

    /**
     * 向hash放进一个map
     *
     * @param cacheKey
     * @param map
     */
    public boolean setDataFromCacheMap(String cacheKey,Map<String,Object> map) {
        boolean result = false;
        try{
            redisTemplate.boundHashOps(cacheKey).putAll(map);
            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 向hash设置过期时间
     *
     * @param cacheKey
     * @param time
     * @param timeUnit
     */
    public void setCacheMapForTime(String cacheKey,Long time,TimeUnit timeUnit) {
        redisTemplate.expire(cacheKey,time,timeUnit);
    }
    /**
     * @param key
     */
    public void delMore(String... key) {
        for (int i = 0; i < key.length; i++) {
            del(key[i]);
        }
    }

    public void del(String key) {
        final String keyf = key;
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.del(keyf.getBytes());
            }
        });
    }

    /**
     * 移除其他库缓存
     */
    public void cacheRemoveOtherDB(String key, int index) {
        JedisConnectionFactory jedisConnectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
        jedisConnectionFactory.setDatabase(index);
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.delete(key);
    }

    /**
     * 判断key是否存在
     * @param key
     * @return
     */
    public boolean exists(String key) {
        return redisTemplate.hasKey(key);
    }

}